package com.subfg.payment.rabiitmq.consumer;


import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONObject;
import com.rabbitmq.client.Channel;
import com.subfg.common.dao.ZlogMQDao;
import com.subfg.common.entity.call.request.RequestPayModel;
import com.subfg.common.entity.call.request.refund.ApplyRefundModel;
import com.subfg.common.entity.common.BatchRecordModel;
import com.subfg.common.entity.excpetion.BusinessExceptionModel;
import com.subfg.common.rabbitmq.constant.ExchangeApi;
import com.subfg.common.rabbitmq.constant.MQSubsetModel;
import com.subfg.common.rabbitmq.constant.QueueContentModel;
import com.subfg.common.rabbitmq.produer.MQSender;
import com.subfg.common.util.common.StringUtil;
import com.subfg.common.util.common.TimeUtil;
import com.subfg.payment.dao.service.CallBackDao;
import com.subfg.payment.rabiitmq.constant.QueueApi;
import com.subfg.payment.rabiitmq.constant.RoutingKeyApi;
import com.subfg.payment.server.PaymentServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;

@Component
public class PaymentRevice {
    private Logger log = LoggerFactory.getLogger(PaymentRevice.class);
    private final Long delayStamp = 20000L;

    @Autowired
    private MQSender mqSender;
    @Autowired
    private ZlogMQDao zlogMQDao;
    @Autowired
    private CallBackDao callBackDao;
    @Autowired
    private PaymentServer paymentServer;


    protected String executeCallBack(String webhook, String body) throws BusinessExceptionModel {
        if (StringUtil.isEmpty(webhook)) {
            log.error("用户设置的异步回调地址为空, 或 不符合规则" + webhook);
            return "Call Back Can Not Be Empty";
        }
        HttpResponse response = HttpRequest.post(webhook)
                .body(body)
                .execute();
        return response.body();
    }
    /** 最终处理 **/
    protected void finalExceptionHanlder(QueueContentModel queueModel, MQSubsetModel mqSubsetModel, Long currentTime) {
        queueModel.setLastDate(currentTime);
        try {
            callBackDao.insertCallBackInfo(mqSubsetModel);
            zlogMQDao.updateUserRequestInfo(new BatchRecordModel<QueueContentModel>(queueModel));
        } catch (Exception e) {
            log.error("队列状态修改失败! 严重错误!!!! 可能会导致消息堆积 或 丢失"+ e);
        }
    }

    @RabbitListener(queues = QueueApi.PAYMENT_QUEUE_PAYMENT_COMMON)
    public void paymentCommon(Message message, QueueContentModel<RequestPayModel> queueModel, Channel channel) throws IOException {
        log.info("正在进行支付模块数据消费!!!! 队列id==>>>{}, 消息主题为==>>>{}, 已消费了==>>>{}次", queueModel.getId(), queueModel.getSubject(), queueModel.getCount());
        Long currentTime = TimeUtil.getCurrentTime();
        RequestPayModel requestPayModel = queueModel.getData();
        String attach = JSONObject.toJSONString(requestPayModel);
        MQSubsetModel mqSubsetModel = MQSubsetModel.builderMqsub(queueModel.getId(), requestPayModel.getWebhook(), 1, attach, currentTime);
        QueueContentModel<MQSubsetModel> subseQueue = new QueueContentModel<MQSubsetModel>(queueModel);
        try {
            if (queueModel.getStatus() == 0 || queueModel.getStatus() == 2) {
                String resultBody = executeCallBack(requestPayModel.getWebhook(), attach);
                if (!resultBody.equals("success")) {
                    throw new BusinessExceptionModel();
                }
                mqSubsetModel.setStatus(1);
                mqSubsetModel.setCallContent(resultBody);
                mqSubsetModel.setCallBackTime(TimeUtil.getCurrentTime());
                subseQueue.setSuccessDate(currentTime);
            }
        }catch (Exception e) {
            log.error("消息消费失败!!!, 错误信息如下" + e);
            log.error("延迟模块消息, 用户消费失败!!! 队列id==>>>{}, 消息主题==>>{}", queueModel.getId(), queueModel.getSubject());
            log.error("为保证消息消费成功!!! 正在使用延迟队列进行重发操作");
            mqSubsetModel.setStatus(-1);
            subseQueue.setData(mqSubsetModel);
            mqSubsetModel.setExceptionName(e.getClass().getName());
            mqSubsetModel.setExceptionInfo(e.getMessage());
            Integer count = queueModel.getCount() + 1;
            subseQueue.setCount(count);
            subseQueue.setDelayTime(count * delayStamp);
            mqSender.sendDelayedMQMessage(ExchangeApi.EXCHANGE_DELAYED, RoutingKeyApi.DELAY_PAYMENT_CALLBACK, subseQueue);
        } finally {
            finalExceptionHanlder(subseQueue, mqSubsetModel , currentTime);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    /** 退款处理 **/
    @RabbitListener(queues = QueueApi.PAYMENT_QUEUE_PAYMENT_REFUND)
    public void refundRevice(Message message, QueueContentModel<ApplyRefundModel> queueModel, Channel channel) throws IOException {
        log.info("正在进行退款队列消费!!! 队列id==>>>{}, 消息主题==>>>{}, 已消费==>>>{}次", queueModel.getId(), queueModel.getSubject(), queueModel.getCount());
        Long currentTime = TimeUtil.getCurrentTime();
        ApplyRefundModel applyRefundModel = queueModel.getData();
        String attach = JSONObject.toJSONString(paymentServer.refundHandler(applyRefundModel.getRefundList()));
        MQSubsetModel mqSubsetModel = MQSubsetModel.builderMqsub(queueModel.getId(), applyRefundModel.getWebhook(), 1,  attach, currentTime);
        QueueContentModel<MQSubsetModel> subseQueue = new QueueContentModel<MQSubsetModel>(queueModel);
        try {
            if (queueModel.getStatus() == 0 || queueModel.getStatus() == 2) {
                String resultBody = executeCallBack(applyRefundModel.getWebhook(), attach);
                if (!resultBody.equals("success")) {
                    log.warn("接口接收响应错误!!!请求失败");
                    throw new BusinessExceptionModel();
                }
                mqSubsetModel.setStatus(1);
                mqSubsetModel.setCallContent(resultBody);
                mqSubsetModel.setCallBackTime(TimeUtil.getCurrentTime());
                subseQueue.setSuccessDate(currentTime);
            }
        } catch (Exception e) {
            log.error("消息消费失败!!!, 错误信息如下" + e);
            log.error("退款信息, 消费失败 !!! 队列id==>>>{}, 消息主题是==>>>{}", queueModel.getId(), queueModel.getSubject());
            log.error("为保证消息消费成功!!! 正在使用延迟队列进行重发操作!!!");
            mqSubsetModel.setStatus(-1);
            subseQueue.setData(mqSubsetModel);
            mqSubsetModel.setExceptionName(e.getClass().getName());
            mqSubsetModel.setExceptionInfo(e.getMessage());
            Integer count = queueModel.getCount() + 1;
            subseQueue.setCount(count);
            subseQueue.setDelayTime(count * delayStamp);
            // TODO 延迟重复
            mqSender.sendDelayedMQMessage(ExchangeApi.EXCHANGE_DELAYED, RoutingKeyApi.DELAY_PAYMENT_CALLBACK, subseQueue);
        } finally {
            finalExceptionHanlder(subseQueue, mqSubsetModel, currentTime);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }

    /** 调用失败后延迟队列 **/
    @RabbitListener(queues = QueueApi.PAYMENT_QUEUE_PAYMENT_DELAY)
    public void delayPaymentRevice(Message message, QueueContentModel<MQSubsetModel> queueModel, Channel channel) throws IOException {
        log.info("正在进行消费延迟支付消息!!!! 队列id==>>>{}, 消息主题为==>>>{}, 已消费==>>>{}", queueModel.getId(), queueModel.getSubject(), queueModel.getCount());
        Long currentTime = TimeUtil.getCurrentTime();
        MQSubsetModel subsetModel = queueModel.getData();
        subsetModel = MQSubsetModel.clearExceptionInfo(subsetModel);
        String attach = (String) subsetModel.getAttach();
        try {
            if (queueModel.getStatus() == 0 || queueModel.getStatus() == 2) {
                String resultBody = executeCallBack(subsetModel.getWebhook(), attach);
                if (!resultBody.equals("success")) {
                    throw new BusinessExceptionModel();
                }
                subsetModel.setStatus(1);
                subsetModel.setCallContent(resultBody);
                subsetModel.setCallBackTime(TimeUtil.getCurrentTime());
                queueModel.setSuccessDate(currentTime);
            }
        } catch (Exception e) {
            log.error("延迟消息消费失败!!!, 错误信息如下"  + e);
            log.error("支付模块消息, 用户消费失败!!! 队列id==>>>{}, 消息主题==>>{}", queueModel.getId(), queueModel.getSubject());
            subsetModel.setStatus(-1);
            queueModel.setData(subsetModel);
            Integer count = queueModel.getCount() + 1;
            subsetModel.setExceptionName(e.getClass().getName());
            subsetModel.setExceptionInfo(e.getMessage());
            if (count <= 6) {
                queueModel.setCount(count);
                queueModel.setDelayTime(count * delayStamp);
                mqSender.sendDelayedMQMessage(ExchangeApi.EXCHANGE_DELAYED, RoutingKeyApi.DELAY_PAYMENT_CALLBACK, queueModel);
            }
        } finally {
            finalExceptionHanlder(queueModel,subsetModel, currentTime);
        }
        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
    }
}
